package com.nightpiter.controller;

import static com.nightpiter.controller.log.Logger.log;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import android.graphics.PointF;
import android.os.Handler;
import android.os.Message;

import com.nightpiter.NightPiter;
import com.nightpiter.R;
import com.nightpiter.controller.algorithms.MetroRouter;
import com.nightpiter.controller.algorithms.MetroRouterState;
import com.nightpiter.controller.algorithms.Route;
import com.nightpiter.controller.threads.MetroModelLoaderThread;
import com.nightpiter.controller.threads.RouterPreparerThread;
import com.nightpiter.controller.threads.RouterSearcherThread;
import com.nightpiter.controller.threads.StationSearcherThread;
import com.nightpiter.model.MetroModel;
import com.nightpiter.model.MetroModelState;
import com.nightpiter.model.objects.Station;
import com.nightpiter.view.MetroView;

/**
 * MVC's Controller class
 * 
 * @author Eldar Abusalimov (eldar.abusalimov@gmail.com)
 * @author Ilya Shurigyn (honorik@gmail.com)
 * 
 */
public class MetroController extends Handler {
	/**
	 * Application context
	 */
	private NightPiter context;

	public static final int MSG_MODEL_STATE_CHANGED = 1;

	public static final int MSG_STATION_RETRIEVED = 2;

	public static final int MSG_ROUTER_STATE_CHANGED = 3;

	public static final int MSG_ROUTES_RETRIEVED = 4;

	/**
	 * default constructor
	 * 
	 * @param context
	 *            the application context
	 */
	public MetroController(NightPiter context) {
		super();
		this.context = context;
		log("Controller instance created");
	}

	/**
	 * should be called after another MVC components created
	 */
	public void init() {
		log("Controller init() call");
		loadModel(com.nightpiter.R.raw.crazy_piter);
	}

	/**
	 * handles messages from the message queue
	 */
	@Override
	public void handleMessage(Message msg) {
		super.handleMessage(msg);
		switch (msg.what) {
		case MSG_MODEL_STATE_CHANGED:
			MetroRouter.onModelStateChanged(getModel(),
					(MetroModelState) msg.obj);
			getView().onModelStateChanged((MetroModelState) msg.obj);
			break;

		case MSG_ROUTER_STATE_CHANGED:
			getView().onRouterStateChanged((MetroRouterState) msg.obj);
			break;

		case MSG_STATION_RETRIEVED:
			getView().onStationRetrieved((Station) msg.obj);
			break;

		case MSG_ROUTES_RETRIEVED:
			getView().onRoutesRetrieved((Route[]) msg.obj);
			break;

		default:
			break;
		}

	}

	/**
	 * starts a new model loading thread
	 * 
	 * @param path
	 *            the file path
	 */
	public void loadModel(String path) {
		(new MetroModelLoaderThread(path, getModel(), this)).start();
	}

	/**
	 * starts a new model loading thread
	 * 
	 * @param resId
	 *            the resource id
	 */
	public void loadModel(int resId) {
		(new MetroModelLoaderThread(resId, getModel(), this)).start();
	}

	/**
	 * starts a new station searching thread
	 * 
	 * @param point
	 */
	public void searchStation(PointF point) {
		(new StationSearcherThread(point, getModel(), this)).start();
	}

	/**
	 * starts a new ruotes computing thread
	 * 
	 * @param fromStation
	 */
	public void prepareRouter(Station fromStation) {
		(new RouterPreparerThread(fromStation, MetroRouter.getInstance(), this))
				.start();
	}

	/**
	 * starts a new routes retrieving thread
	 * 
	 * @param toStation
	 */
	public void searchRoutes(Station toStation) {
		(new RouterSearcherThread(toStation, MetroRouter.getInstance(), this))
				.start();
	}

	/**
	 * gets a list of files from the maps directory
	 * 
	 * @return the list of files
	 */
	public List<String> getFilesList() {
		List<String> filesList = new ArrayList<String>();
		filesList.clear();
		File dir = new File(context.getString(R.string.maps_dir));
		if (!dir.exists()) {
			dir.mkdir();
		}
		for (File file : dir.listFiles()) {
			String fn = file.getName();
			if (fn.endsWith(context.getString(R.string.maps_extension))) {
				filesList.add(fn);
			}
		}
		return filesList;
	}

	/**
	 * @return the context
	 */
	protected NightPiter getContext() {
		return context;
	}

	/**
	 * @return
	 * @see com.nightpiter.NightPiter#getModel()
	 */
	protected MetroModel getModel() {
		return context.getModel();
	}

	/**
	 * @return
	 * @see com.nightpiter.NightPiter#getView()
	 */
	protected MetroView getView() {
		return context.getView();
	}

}
